package com.deployment;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.jar.JarOutputStream;

import javax.enterprise.deploy.shared.StateType;
import javax.enterprise.deploy.shared.factories.DeploymentFactoryManager;
import javax.enterprise.deploy.spi.DeploymentManager;
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.TargetModuleID;
import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException;
import javax.enterprise.deploy.spi.status.DeploymentStatus;
import javax.enterprise.deploy.spi.status.ProgressObject;

import org.jboss.as.ee.deployment.spi.DeploymentManagerImpl;
import org.jboss.as.ee.deployment.spi.DeploymentMetaData;
import org.jboss.as.ee.deployment.spi.JarUtils;
import org.jboss.as.ee.deployment.spi.factories.DeploymentFactoryImpl;

public class JSR88Deployer {

	public static DeploymentManager getDeploymentManager(String _strServer,
			String _strPort) {
		// Register for AS7!
		DeploymentFactoryImpl.register();

		// Get a DeploymentFactoryManager instance:
		DeploymentFactoryManager dfm = DeploymentFactoryManager.getInstance();

		// Try to get a DeploymentManager from the factory.
		DeploymentManager dm = null;
		try {
			// "DEPLOYER_URI" is "http://org.jboss.deployment/jsr88":
			String sURL = DeploymentManagerImpl.DEPLOYER_URI + "?targetType=as7&serverHost=" + _strServer + "&serverPort=" + _strPort;
			dm = dfm.getDeploymentManager(sURL, null, null);
		} catch (DeploymentManagerCreationException e) {
			System.err.println("Could not get DeploymentManager: " + e.toString());
		}

		return dm;
	}

	/**
	 * Creates a deployment plan (zip file) in the temp dir.
	 * 
	 * @param deploymentFile
	 *            This is the file to be deployed (full path)
	 * @return The file which contains the deployment plan
	 * @throws Exception
	 *             All exceptions...
	 */
	private static File createDeploymentPlan(String deploymentFile)
			throws Exception {
		// Create a temp zip file for deployment plan
		File deploymentPlan = File.createTempFile("deploymentplan", ".zip");
		deploymentPlan.deleteOnExit();

		JarOutputStream jos = new JarOutputStream(new FileOutputStream(
				deploymentPlan));

		// Setup deployment plan meta data with proprietary descriptor
		DeploymentMetaData metaData = new DeploymentMetaData(deploymentFile);

		// Add the meta data to the deployment plan
		String metaStr = metaData.toXMLString();

		JarUtils.addJarEntry(jos, DeploymentMetaData.ENTRY_NAME, new ByteArrayInputStream(metaStr.getBytes()));
		jos.flush();
		jos.close();

		return deploymentPlan;
	}

	/**
	 * Deploy a file using a deployment manager.
	 * 
	 * @param strPath
	 *            Path to the file, e.g. "c:\temp"
	 * @param module
	 *            The file name, e.g. "MyApp.ear"
	 * @param manager
	 *            This DeploymentManager is used for deployment.
	 * @return A ProgressObject, or NULL is deployment failed because of errors
	 *         in the file.
	 * @throws Exception
	 *             Any errors (no good style ;-) )
	 */
	private static ProgressObject jsr88Deployment(String strPath,
			String module, DeploymentManager manager) throws Exception {
		// Get the deployment manager and the distribution targets
		Target[] targets = manager.getTargets();

		// Build a deployment plan (which is a zip file in the temp dir):
		File deploymentPlan = createDeploymentPlan(module);

		// Deploy the specified file.
		// Step 1: distribute it to the server:
		File moduleArchive = new File(strPath, module);
		ProgressObject progress = manager.distribute(targets, moduleArchive,
				deploymentPlan);
		DeploymentStatus status = progress.getDeploymentStatus();
		if (status.getState() == StateType.FAILED) {
			// Distribution may fail, if e.g. "ejb-jar.xml" is broken!
			// "status.getMessage()" might throw a "ClassNotFoundException", if
			// the exceptions from the server are in Jars
			// which are not included by this client app.
			System.out.println("Deployment failed: " + status.getMessage());
			return null;
		}

		// Now wait for completion of distribution:
		waitForCompletion(status);

		// Step 2: Start the modules whose IDs are returned by the "distribute"
		// operation.:
		TargetModuleID[] moduleIDs = progress.getResultTargetModuleIDs();
		progress = manager.start(moduleIDs);
		status = progress.getDeploymentStatus();

		// Wait for completion of the "start" operation:
		waitForCompletion(status);

		return progress;
	}

	public static void waitForCompletion(DeploymentStatus status)
			throws InterruptedException {
		// wait for the deployment to finish
		while (StateType.RUNNING == status.getState())
			Thread.sleep(100);
	}

	public static void main(String[] args) throws Exception {
		// Get a Deployment manager:
		DeploymentManager dm = getDeploymentManager("localhost", "19999");
		if (dm == null) {
			return;
		}

		// Deploy file:
		ProgressObject po = JSR88Deployer.jsr88Deployment("c:\\temp\\", "Stateless.ear", dm);

		// Just some debugging code: output module IDs of deployed code
		// (progress object is only returned on success):
		if (po != null) {
			System.out.println("Deployed file. ModuleIDs: ");
			TargetModuleID[] modules = po.getResultTargetModuleIDs();
			for (int intIndexModule = 0; intIndexModule < modules.length; intIndexModule++) {
				System.out.println("\t" + modules[intIndexModule].toString());
			}
		}
	}
}
